/*LICENSE_BEGIN
 * ******************************************************************
 * All original parts of SoccerScope2003 have copyright (2003) by
 * Team YowAI, represented by Mr. Shuhei Shiota
 * The Department of Creative Informatics
 * The Graduate School of Information Science and Technology
 * The University of Tokyo
 * 
 * Additional classes (except libraries in /lib) were developed by 
 * the Dainamite Robocup-Team of the DAI-Labor, TU-Berlin 
 * (www.dai-labor.de)
 * 
 * Extended/new classes/packages are:
 *   soccerscope.analyzer.LogfileAnalyzer
 *   soccerscope.daistatistic.*
 *   soccerscope.daistatistic.charts.*
 *   soccerscope.daistatistic.tools.*
 *   soccerscope.db.*
 *   soccerscope.dialog.*
 *   soccerscope.model.PlayerWorldModel
 *   soccerscope.model.SimplePlayer
 *   soccerscope.net.AgentConnector
 *   soccerscope.training.*
 *   soccerscope.training.conditions.*
 * ******************************************************************
LICENSE_END*/
package soccerscope.daistatistic.charts;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.GridLayout;
import java.awt.Label;
import java.awt.Menu;
import java.awt.MenuBar;
import java.awt.MenuItem;
import java.awt.Panel;
import java.awt.Scrollbar;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.awt.image.BufferedImage;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;

import soccerscope.daistatistic.Register;
import soccerscope.daistatistic.StatisticDialog;
import soccerscope.daistatistic.tools.JPGWriter;

/**
 * this class represents a frame which shows a jFreeChart and save's a jfc image
 * 
 */
public class OutputFrame extends Frame implements ActionListener,
		WindowListener, ComponentListener, MouseListener, AdjustmentListener {

	private static final long serialVersionUID = 3544390309871106359L;

	private MenuItem saveChart; // allocate the save menu item

	private String fileName = "outputFrame"; // the file name

	// init size and location
	private int sizeX = 500;

	private int sizeY = 380;

	// private int locationX = 300;

	// private int locationY = 300;

	// the info panel and its info labels
	Panel textPanel = new Panel();

	Label textFieldAverage = new Label();

	Label textFieldInfo1 = new Label();

	Label textFieldInfo2 = new Label();

	// the jFreeChart and its panel
	ChartPanel chartPanel;

	JFreeChart jfc;

	// the scrollbar shown under the jFreeChart image
	Scrollbar scrollHor = new Scrollbar();

	int scrollBarHeigh = 20;

	/**
	 * constructor init the frame and add the menu bar
	 */
	public OutputFrame() {

		// set false to prevent unknown bug at first load of the frame
		setVisible(false);

		// size and location
		setSize(this.sizeX, this.sizeY);
		setLocation(300, 300);

		// add menu bar with save entry
		MenuBar menuBar = new MenuBar();
		this.saveChart = new MenuItem("Save Chart");
		Menu fileMenu = new Menu("File");
		fileMenu.add(this.saveChart);
		menuBar.add(fileMenu);
		this.setMenuBar(menuBar);

		// set main layout and titel
		this.setLayout(new FlowLayout(FlowLayout.CENTER, 0, 0));
		this.setTitle("Note: press info text to refresh window");

		// set layout of text panel and add all info labels
		this.textPanel.setLayout(new GridLayout(3, 1, 0, 0));
		this.textPanel.setBackground(Color.LIGHT_GRAY);
		this.textPanel
				.setPreferredSize(new Dimension(this.getSize().width, 70));
		this.textPanel.add(this.textFieldAverage);
		this.textPanel.add(this.textFieldInfo1);
		this.textPanel.add(this.textFieldInfo2);

		this.textFieldAverage.setPreferredSize(new Dimension(100, 20));
		this.textFieldAverage.setText("Average: ");
		this.textFieldInfo1.setPreferredSize(new Dimension(100, 20));
		this.textFieldInfo1.setText("");
		this.textFieldInfo2.setPreferredSize(new Dimension(100, 20));
		this.textFieldInfo2.setText("");

		// create a jFreeChart and put an empty dataset into the chart
		org.jfree.data.category.DefaultCategoryDataset dcd = new org.jfree.data.category.DefaultCategoryDataset();
		this.jfc = ChartFactory.createLineChart("Statistics Chart", "Time",
				"Value", dcd, PlotOrientation.VERTICAL, true, true, true);

		// create a chart panel and put the jFreeChart in
		this.chartPanel = new ChartPanel(this.jfc);
		this.chartPanel.addMouseListener(this);
		this.chartPanel
				.setPreferredSize(new Dimension(
						this.getSize().width,
						this.getSize().height
								- (this.textPanel.getY()
										+ this.textPanel.getSize().height + this.scrollBarHeigh)));

		// init the scrollbar
		this.scrollHor.setOrientation(Scrollbar.HORIZONTAL);
		this.scrollHor.setPreferredSize(new Dimension(this.getSize().width,
				this.scrollBarHeigh));

		// add all components to the layout
		add(this.textPanel);
		add(this.chartPanel);
		add(this.scrollHor);

		// add all needed listener
		addWindowListener(this);
		addComponentListener(this);
		this.textFieldAverage.addMouseListener(this);
		this.textFieldInfo1.addMouseListener(this);
		this.textFieldInfo2.addMouseListener(this);
		this.saveChart.addActionListener(this);
		this.textPanel.addMouseListener(this);
		this.scrollHor.addAdjustmentListener(this);

		// show the frame and update the dimensions of all components
		doLayout();
		updateSize();
		setVisible(true);
	}

	/**
	 * setting the jFreeChart to show
	 * 
	 * @param JFreeChart
	 * @param int
	 *            the number of values (cycles) that the dataset in jfc contains
	 */
	public void setFreeChart(JFreeChart chart, int length) {
		this.jfc = chart;
		this.chartPanel.setChart(this.jfc);
		this.scrollHor.setMaximum(length); // set new navigation scrollbar
		// length
		repaint();
	}

	/**
	 * setting the file name
	 * 
	 * @param String
	 *            name
	 */
	public void setFileName(String name) {
		this.fileName = name;
	}

	/**
	 * set the average to show in the average line
	 * 
	 * @param double
	 */
	public void setAverage(double average) {
		this.textFieldAverage.setText("  Average: " + Double.toString(average));
	}

	/**
	 * set the info text 1
	 * 
	 * @param String
	 */
	public void setInfo1(String text) {
		this.textFieldInfo1.setText("  " + text);
	}

	/**
	 * set the info text 2
	 * 
	 * @param String
	 */
	public void setInfo2(String text) {
		this.textFieldInfo2.setText("  " + text);
	}

	/**
	 * repaint the context
	 */
	@Override
	public void repaint() {
		updateSize();
		paint(this.getGraphics());
	}

	/**
	 * updates the size of all components, so that the components fit to the
	 * frame size
	 */
	void updateSize() {
		doLayout();
		this.textPanel
				.setPreferredSize(new Dimension(this.getSize().width, 70));
		this.scrollHor.setPreferredSize(new Dimension(this.getSize().width,
				this.scrollBarHeigh));
		this.chartPanel
				.setPreferredSize(new Dimension(
						this.getSize().width,
						this.getSize().height
								- (this.textPanel.getY()
										+ this.textPanel.getSize().height + this.scrollBarHeigh)));
		doLayout();
	}

	/**
	 * action handler for the menu bar
	 * 
	 * @param ActionEvent
	 *            arg0, the sender
	 */
	public void actionPerformed(ActionEvent arg0) {
		Object o = arg0.getSource();
		if (o == this.saveChart) {
			saveChart();
			return;
		}
	}

	/**
	 * save the actual chart to a jpg image, using tools.JPGWriter
	 */
	private void saveChart() {

		// make a string array with text lines to write into the image
		String[] textLines = new String[3];
		textLines[0] = this.textFieldAverage.getText();
		textLines[1] = this.textFieldInfo1.getText();
		textLines[2] = this.textFieldInfo2.getText();

		// create the buffered image
		BufferedImage picture = JPGWriter.writeStringsToImage(textLines,
				this.jfc.createBufferedImage(this.getSize().width, this
						.getSize().height));

		// try to save the file
		try {
			JPGWriter.save(picture, this.fileName);
		} catch (Exception e) {
		}
	}

	/**
	 * process window event windowClosing inform statistic dialog that output
	 * frame is closing
	 * 
	 * @param WindowEvent
	 */
	public void windowClosing(WindowEvent arg0) {
		StatisticDialog.chartFrameClosed();
		dispose();
	}

	// unused window events
	public void windowOpened(WindowEvent arg0) {
	}

	public void windowClosed(WindowEvent arg0) {
	}

	public void windowIconified(WindowEvent arg0) {
	}

	public void windowDeiconified(WindowEvent arg0) {
	}

	public void windowActivated(WindowEvent arg0) {
	}

	public void windowDeactivated(WindowEvent arg0) {
	}

	/**
	 * process mouse event mouse pressed sets shown cycle or refreshs the frame
	 * 
	 * @param MouseEvent
	 */
	public void mousePressed(MouseEvent arg0) {
		Object o = arg0.getSource(); // get sender, chartPanel or textPanel
		if (o == this.chartPanel) { // if sender was the chartPanel
			try { // try to get chart coordinates of mouse position
				String tmp = this.chartPanel.getEntityForPoint(arg0.getX(),
						arg0.getY()).getToolTipText();

				// extact x value out of the entity string
				tmp = tmp.substring(tmp.indexOf("(") + 1, tmp.indexOf(","));

				// set the new cycle position to scrollbar
				this.scrollHor.setValue(Integer.parseInt(tmp));

				// skip to selected cycle
				Register.soccerScope.getScenePlayer().skip(
						Integer.parseInt(tmp));
			} catch (Exception e) {
			} // only exception is when clicked on a position on screen
			// without a drawn function
			// so nothing is to do here - user must click to an other position
			// ;)
		} else {
			// repeat action in statistic dialog / means refresh chart at online
			// analysis
			StatisticDialog.action();
		}
	}

	// unused mouse events
	public void mouseClicked(MouseEvent arg0) {
	}

	public void mouseReleased(MouseEvent arg0) {
	}

	public void mouseEntered(MouseEvent arg0) {
	}

	public void mouseExited(MouseEvent arg0) {
	}

	/**
	 * process adjustment event adjustment value changed skip to selected cycle
	 * 
	 * @param MouseEvent
	 */
	public void adjustmentValueChanged(AdjustmentEvent arg0) {
		Register.soccerScope.getScenePlayer().skip(this.scrollHor.getValue());

	}

	/**
	 * process component listener component resized when window is resized we
	 * need to recalculate component sizes and repaint them
	 * 
	 * @param ComponentEvent
	 */
	public void componentResized(ComponentEvent arg0) {
		repaint();

	}

	// unused component events
	public void componentMoved(ComponentEvent arg0) {
	}

	public void componentShown(ComponentEvent arg0) {
	}

	public void componentHidden(ComponentEvent arg0) {
	}
}
